RubyのHash型をjsonモジュールのto_jsonを使うときに気をつけたいこと
サーモン大好き横山です。
今回はrubyのjsonモジュールの to_json
メソッドで気になる挙動があったので紹介します。
用途
そもそもこちらのメソッドは、RubyのHashやArray等のデータ型を、json形式の文字列に変換してくれるメソッドです。
コード
#!/usr/bin/env ruby # demo.rb require 'json' data = { "num" => 1, "string" => "abc", "array" => [1, 2, 3], "hash" => {"key1" => "value1", "key2" => "value2"} } puts data.to_json
結果
$ ruby demo.rb {"num":1,"string":"abc","array":[1,2,3],"hash":{"key1":"value1","key2":"value2"}}
jq
を使うと見やすく表示できます。
$ ruby demo.rb | jq . { "num": 1, "string": "abc", "array": [ 1, 2, 3 ], "hash": { "key1": "value1", "key2": "value2" } }
to_json メソッドの気になる挙動
表題についてですが、Hash型のキーで シンボル
と 文字列
が同名のものが存在すると同一キーのハッシュとしてjsonを生成してしまいます。
これは、RFC4627 2.2 Objects
の以下の記述に反しています。
The names within an object SHOULD be unique. 1
コード
#!/usr/bin/env ruby # demo2.rb require 'json' data = { key: 1, "key" => 2 } puts data.to_json
実行結果
$ ruby demo2.rb {"key":1,"key":2}
問題点
このままjqに渡すと片方のデータのみ表示してしまいます。
実行結果
$ ruby demo2.rb | jq . { "key": 2 }
demo2.rb
のHashの要素を入れ替えた demo3.rb
で実行するとこうなります。
コード
#!/usr/bin/env ruby # demo3.rb require 'json' data = { "key" => 2, key: 1 } puts data.to_json
実行結果
$ ruby demo3.rb {"key":2,"key":1} $ ruby demo3.rb | jq . { "key": 1 }
ハッシュの後ろのデータが最終的にjqで出力されます。
まとめ
以上のことから、Hash型のキーで シンボル
と 文字列
が同名のものが存在するときの to_json
の挙動は重複キーを含まれるjsonが生成されます。
jqを通した場合、ハッシュの後ろのデータが最終的にjqで出力されます。
他のサービスではどういう挙動をするのかわかりませんので、なるべくHash型をjsonに変換する時は気をつけて to_json
メソッドを呼び出すようにコードを書いたほうがいいですね。